# # 创建进程执行多任务
import time
from multiprocessing import Process, Pool, Queue, Pipe


# #
# # 方法一：使用process类创建进程
# # 吃饭任务
# def eat():
#     for i in range(6):
#         print("正在吃饭....")
#         time.sleep(0.3)
#
#
# # 做作业任务
# def work():
#     for i in range(6):
#         print('正在做作业....')
#         time.sleep(0.3)
#
#
# if __name__ == '__main__':
#     # 创建一个子进程，每个任务由一个独立的子进程来完成
#     p1 = Process(target=eat, name="进程1")
#     p2 = Process(target=work, name="进程2")
#
#     # 启动进程
#     p1.start()
#     p2.start()
#
#     # 主进程自动等待，所有的子进程执行各自的任务，直到所有的子进程都结束从，主进程才结束


# 方法二：继承process类创建进程
# class EatProcess(Process):
#     """ 写一个自定义的类，继承Process"""
#
#     def __init__(self, name):
#         super().__init__()  # 必须有
#         self.name = name
#
#     def run(self) -> None:
#         for i in range(6):
#             print(f'进程{self.name}:正在吃饭...')
#             time.sleep(0.3)
#
#
# class WorkProcess(Process):
#     """ 写一个自定义的类，继承Process"""
#
#     def __init__(self, name):
#         super().__init__()  # 必须有
#         self.name = name
#
#     def run(self) -> None:
#         for i in range(6):
#             print(f'进程{self.name}:正在做作业...')
#             time.sleep(0.3)
#
#
# if __name__ == '__main__':
#
#     p1 = EatProcess('process-1')
#     p2 = EatProcess('process-2')
#
#     p1.start()
#     # 子进程调用join函数，主进程被阻塞，直到当前子进程结束
#     p1.join()
#     p2.start()

# # 方法三，进程池创建进程
#
# # 吃饭任务
# def eat(name):
#     for i in range(6):
#         print(f"正在吃饭....${name}")
#         time.sleep(0.3)
#
#
# # 做作业任务
# def work():
#     for i in range(6):
#         print('正在做作业....')
#         time.sleep(0.3)
#
#
# # 打游戏任务
# def game():
#     for i in range(6):
#         print('正在打游戏....')
#         time.sleep(0.3)
#
#
# if __name__ == '__main__':
#     process_pool = Pool(2)
#     # apply函数-用来执行任务，但这个是一个阻塞的函数（主进程）
#     # 从进程池中请求一个新的进程去执行eat
#     # process_pool.apply(eat, args=('张三',))
#     # process_pool.apply(work)
#
#     # async：异步调用（非阻塞）
#     process_pool.apply_async(eat, args=('张三',))
#     process_pool.apply_async(work)
#     # close表示进程池关闭，表示进程池不再接受新的请求
#     process_pool.close()
#     # 在进程池关闭后，再次调用game，执行失败
#     # process_pool.apply_async(game)
#     # 使用进程池的异步调用，需要使用join，让主进程等待
#     process_pool.join()

# 多进程中不能使用全局变量共享数据
# my_list = []
#
#
# def add_data():
#     for i in range(6):
#         my_list.append(i)
#         time.sleep(0.3)
#
#
# def read_data():
#     print(my_list)
#
#
# if __name__ == '__main__':
#     p1 = Process(target=add_data)
#     p2 = Process(target=read_data)
#
#     p1.start()
#     p1.join()
#     p2.start()

# # 方法一，进程通信：Queue队列进行多进程通信
# my_list = []
#
#
# def add_data(q: Queue):
#     for i in range(6):
#         q.put(f'数据{i}')
#         time.sleep(0.3)
#
#
# def read_data(q: Queue):
#     while True:
#         # get函数是一个阻塞的函数，get从队列中获取一个值，并且将这个值从队列中删除
#         value = q.get()
#         print(value)
#         time.sleep(0.4)
#
#
# if __name__ == '__main__':
#     q = Queue(100)
#     p1 = Process(target=add_data, args=(q,))  # 往队列中存数据
#     p2 = Process(target=read_data, args=(q,))  # 从队列中获取数据
#
#     p1.start()
#     p2.start()
#     p1.join()
#     # 子进程强制关掉
#     p1.terminate()
#     p2.terminate()

# 方法二，管道通信Pipe

def add_data(pi: Pipe):
    for i in range(6):
        pi.send(f'数据{i}')
        time.sleep(0.3)


def read_data(pi: Pipe):
    while True:
        value = pi.recv()
        print(value)
        time.sleep(0.4)


if __name__ == '__main__':
    # 创建管道，需要两个端点
    send_pi, recv_pi = Pipe()
    p1 = Process(target=add_data, args=(send_pi,))  # 往队列中存数据
    p2 = Process(target=read_data, args=(recv_pi,))  # 从队列中获取数据
    p1.start()
    p2.start()
    p1.join()
    p1.terminate()
    p2.terminate()
